/**
 * Copyright (C), 2015-2019, XXX有限公司
 * FileName: JobServiceImpl
 * Author:   zhouheng
 * Date:     2019/6/25 23:10
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.zhouh.golden.service.impl;

import com.zhouh.golden.common.annotation.CronTag;
import com.zhouh.golden.common.service.impl.BaseService;
import com.zhouh.golden.dao.JobMapper;
import com.zhouh.golden.domain.Job;
import com.zhouh.golden.service.JobService;
import com.zhouh.golden.util.ScheduleUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author zhouheng
 * @create 2019/6/25
 * @since 1.0.0
 */
@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JobServiceImpl extends BaseService<Job> implements JobService {

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private JobMapper jobMapper;

    @PostConstruct
    public void init(){
        // 获取所有job
        List<Job> scheduleJobs =  this.mapper.selectAll();
        scheduleJobs.forEach(scheduleJob -> {
            CronTrigger cronTrigger = ScheduleUtil.getCronTrigger(scheduler, scheduleJob.getJobId());
            if (cronTrigger == null) {
                ScheduleUtil.create(scheduler, scheduleJob);
            } else {
                ScheduleUtil.update(scheduler, scheduleJob);
            }
        });
    }

    /**
     * @description: 新增定时任务
     * @date: 2019/6/26 23:22
     * @author:zhouheng
     */
    @Transactional
    public void addJob(Job job) {
        job.setCreateTime(new Date());
        job.setStatus(Job.ScheduleStatus.PAUSE.getValue());
        this.save(job);
        ScheduleUtil.create(scheduler, job);
    }

    @Transactional
    public void updateJob(Job job) {
        ScheduleUtil.update(scheduler, job);
        this.updateNotNull(job);
    }

    /**
     * @description: 批量删除
     * @date: 2019/6/26 23:28
     * @author:zhouheng
     */
    @Transactional
    public void deleteBatch(String jobIds) {
        List<String> list = Arrays.asList(jobIds.split(","));
        list.forEach(jobId -> ScheduleUtil.deleteScheduleJob(scheduler, Long.valueOf(jobId)));
        this.batchDelete(list, "jobId", Job.class);
    }


    /**
     * @description: 批量更新
     * @date: 2019/6/26 23:34
     * @author:zhouheng
     */
    @Transactional
    public int updateBatch(String jobIds, String status) {
        List<String> list = Arrays.asList(jobIds.split(","));
        Example example = new Example(Job.class);
        example.createCriteria().andIn("jobId", list);
        Job job = new Job();
        job.setStatus(status);
        return this.jobMapper.updateByExampleSelective(job, example);
    }

    /**
     * @description: 执行任务
     * @date: 2019/6/26 23:34
     * @author:zhouheng
     */
    @Transactional
    public void run(String jobIds) {
        String[] list = jobIds.split(",");
        Arrays.stream(list).forEach(jobId -> ScheduleUtil.run(scheduler, this.selectByKey(Long.valueOf(jobId))));
    }

    /**
     * @description: 批量暂停
     * @date: 2019/6/26 23:36
     * @author:zhouheng
     */
    @Transactional
    public void pause(String jobIds) {
        String[] list = jobIds.split(",");
        Arrays.stream(list).forEach(jobId -> ScheduleUtil.pauseJob(scheduler, Long.valueOf(jobId)));
        this.updateBatch(jobIds, Job.ScheduleStatus.PAUSE.getValue());
    }

    @Transactional
    public void resume(String jobIds) {
        String[] list = jobIds.split(",");
        Arrays.stream(list).forEach(jobId -> ScheduleUtil.resumeJob(scheduler, Long.valueOf(jobId)));
        this.updateBatch(jobIds, Job.ScheduleStatus.NORMAL.getValue());
    }

    @SuppressWarnings("rawtypes")
    public List<Job> getSysCronClazz(Job job) {
        Reflections reflections = new Reflections("com.zhouh.golden.task.TestTask");
        List<Job> jobList = new ArrayList<>();
        Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(CronTag.class);

        for (Class cls : annotated) {

            String clsSimpleName = cls.getSimpleName();
            Method[] methods = cls.getDeclaredMethods();
            for (Method method : methods) {
                Job job1 = new Job();
                String methodName = method.getName();
                Parameter[] methodParameters = method.getParameters();
                String params = String.format("%s(%s)", methodName, Arrays.stream(methodParameters).map(item -> item.getType().getSimpleName() + " " + item.getName()).collect(Collectors.joining(", ")));

                job1.setBeanName(StringUtils.uncapitalize(clsSimpleName));
                job1.setMethodName(methodName);
                job1.setParams(params);
                jobList.add(job1);
            }
        }
        return jobList;
    }

}